#include "xsRendPCH.hpp"

#include <map>

#include "rend_FontImpl.h"

namespace xs
{
//=================================================================================================
std::wstring get_path(std::wstring file) // przeniesc z tad? jak bedzie trzeba gdzie indziej uzyc
{
	std::wstring path = file;
	int pos = (int)file.size();
	while(pos>=0 && !(file[pos]== L'\\' || file[pos]==L'/'))
		pos--;
	path.resize(pos+1);
	return path;
}

//=================================================================================================
// FontImpl::FontImpl
//=========

FontImpl::FontImpl(const wchar_t *_name, Renderer *_xse):
xse(_xse)
{
	File file;
	load_file(_name, file);
	char *data = new char[file.get_size()+1];
	data[file.get_size()] = 0;
	memcpy(data, file.get_data(), file.get_size());

	TiXmlDocument doc;
	doc.Parse(data);
	delete [] data;

	std::wstring path = get_path(_name);

	TiXmlElement *el;
	el = doc.FirstChildElement("font")->FirstChildElement("common");
	el->Attribute("lineHeight", &line_height);

	el = doc.FirstChildElement("font")->FirstChildElement("pages");
	el = el->FirstChildElement("page");
	while(el)
	{
		std::wstring file;
		int id;

		el->Attribute("id", &id);
		file = str_to_wstr(el->Attribute("file"));

		pages[id] = xse->get_texture((path+file).c_str());

		el = el->NextSiblingElement("page");
	}

	el = doc.FirstChildElement("font")->FirstChildElement("chars")->FirstChildElement("char");
	while(el)
	{
		Character c;

		int id;
		el->Attribute("id", &id);

		el->Attribute("x", &c.x);
		el->Attribute("y", &c.y);
		el->Attribute("width", &c.width);
		el->Attribute("height", &c.height);
		el->Attribute("xoffset", &c.xoffset);
		el->Attribute("yoffset", &c.yoffset);
		el->Attribute("xadvance", &c.xadvance);
		el->Attribute("page", &c.page);

		chars[id] = c;

		el = el->NextSiblingElement("char");
	}

	if(!doc.FirstChildElement("font")->FirstChildElement("kernings")) return;
	el = doc.FirstChildElement("font")->FirstChildElement("kernings")->FirstChildElement("kerning");
	while(el)
	{
		int f, s;
		int val;

		el->Attribute("first", &f);
		el->Attribute("second", &s);
		el->Attribute("amount", &val);

		Kerning ker;
		ker.first = (unsigned short)f;
		ker.second = (unsigned short)s;

		kernings[ker.id] = val;

		el = el->NextSiblingElement("kerning");
	}
}

//=================================================================================================
// FontImpl::~FontImpl

FontImpl::~FontImpl()
{
}

//=================================================================================================
// FontImpl::print
//=========

void FontImpl::print(const int &x, const int &y, const wchar_t *text, const Color &color)
{
    xse->set_texture_filter(xs::TF_LINEAR);
	int curr_x = x;
	Quad q;
	Kerning ker;
	int tex_width, tex_height;
	q.blend = xs::Blends::ALPHA;
	for(int i=0; i<4; i++)
	{
		q.v[i].color = color;
		q.v[i].z = 0;
		q.v[i].y = (f32)y;
	}

	q.v[2].y = q.v[3].y = (f32)y-32;

	for(int i=0; text[i]; i++)
	{
		Character c;
		if(text[i] == L'\n') continue; // bugfix

		if(chars.find(text[i]) != chars.end())
			c = chars[text[i]];
		else 
			c = chars[L'?'];


		q.texture = pages[c.page];
		xse->get_texture_size(q.texture, tex_width, tex_height);

		// pos
		q.v[0].x = (f32)curr_x;
		q.v[1].x = (f32)curr_x + (f32)c.width;
		q.v[2].x = q.v[1].x;
		q.v[3].x = q.v[0].x;

		q.v[1].y = q.v[0].y = (f32)y;
		q.v[2].y = q.v[3].y = (f32)y+(f32)c.height;

		for(int t=0; t<4; t++)
		{
			q.v[t].x += c.xoffset;
			q.v[t].y += c.yoffset;
		}

		// tex-coords
		q.v[0].u = q.v[3].u = (c.x)/(float)tex_width;
		q.v[1].u = q.v[2].u = (c.x+c.width)/(float)tex_width;

		q.v[0].v = q.v[1].v =(c.y)/(float)tex_height;
		q.v[2].v = q.v[3].v =(c.y+c.height)/(float)tex_height;

		//kerning
		if(i)
		{
			ker.first = text[i-1];
			ker.second = text[i];

			if(kernings.count(ker.id))
			{
				for(int t=0; t<4; t++)
					q.v[t].x += kernings[ker.id];
				curr_x += kernings[ker.id];
			}
		}

		xse->render_quad(q);

		curr_x += c.xadvance;
	}
}

//=================================================================================================
// FontImpl::print_ex
//=========

void FontImpl::print_ex(const int &x, const int &y, const wchar_t *text, 
		const Color &color, const int &line_width)
{
	int curr_y = y;
	int x_width = 0;
	int curr_word_width = 0;
	// ta funkcja jest bardzo nie wydajna, coz
	std::wstring word;
	for(unsigned int i=0; text[i]; i++)
	{
		word += text[i];
		x_width += chars[text[i]].xadvance;
		curr_word_width += chars[text[i]].xadvance;

		if(text[i]==L' ' || text[i]==L'\t' || text[i]==L'\n')
		{
			if(x_width <= line_width)
				print(x+x_width-curr_word_width,curr_y, word.c_str(), color);
			else
			{
				curr_y -= line_height;
				print(x,curr_y, word.c_str(), color);

				x_width = curr_word_width;
			}

			if(text[i]==L'\n')
			{
				curr_word_width =0;
				x_width = 0;
				curr_y +=line_height;
			}

			curr_word_width = 0;
			word.clear();
		} 
	}
	if(x_width <= line_width)
		// miesci sie
		print(x+x_width-curr_word_width,curr_y, word.c_str(), color);
	else
		// nie miesci sie
		print(x,curr_y-line_height, word.c_str(), color);
}

//=================================================================================================
// FontImpl::get_width
//=========

unsigned int FontImpl::get_width(const wchar_t *text)
{
	unsigned int result = 0;
	unsigned int curr = 0;
	Kerning ker;

	for(unsigned int i=0; text[i]; i++)
	{
		if(text[i]=='\n')
			curr=0;
		else
			curr += chars[text[i]].xadvance;

		//kerning
		if(i)
		{
			ker.first = text[i-1];
			ker.second = text[i];

			if(kernings.count(ker.id))
				curr += kernings[ker.id];
		}

		result = std::max(curr, result);
	}

	return result;
}

//=================================================================================================
// FontImpl::get_line_height
//=========

unsigned int FontImpl::get_line_height()
{
	return (unsigned int)line_height;
}

}